package com.liveneo.adapter.mobile.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.net.ssl.SSLContext;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

@SuppressWarnings("deprecation")
public class HttpUtils {
    private static HttpUtils              instance;
    private static Map<String, HttpUtils> instances;
    private static List<Header>           headers;
    private static int                    connectTimeout        = 3000;
    private static int                    connectRequestTimeout = 6000;
    private HttpHost                      proxy;
    private RequestConfig                 requestConfig, proxyConfig;
    private BasicCookieStore              cookieStore;
    private CloseableHttpClient           httpclient;
    private SSLConnectionSocketFactory    sslSocketFactory;

    private HttpUtils() {
        cookieStore = new BasicCookieStore();
        sslSocketFactory = this.getSslSocketFactory();
        requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setConnectionRequestTimeout(connectRequestTimeout).build();
        httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore).setDefaultRequestConfig(requestConfig).setSSLSocketFactory(sslSocketFactory)
                .build();
        this.defaultHeader();
    }

    public static HttpUtils getInstance() {
        synchronized (HttpUtils.class) {
            if (headers == null) {
                headers = new ArrayList<Header>();
            }
            if (instance == null) {
                instance = new HttpUtils();
            }
        }
        return instance;
    }

    public static HttpUtils getInstance(String client) {
        synchronized (HttpUtils.class) {
            if (headers == null) {
                headers = new ArrayList<Header>();
            }
            if (instances == null) {
                instances = new HashMap<String, HttpUtils>();
            }
            if (!instances.containsKey(client)) {
                instances.put(client, new HttpUtils());
            }
        }
        return instances.get(client);
    }

    public List<Cookie> getCookies() {
        return cookieStore.getCookies();
    }

    public HttpHost getProxy() {
        return proxy;
    }

    /**
     * 添加请求Heander
     * @param name
     * @param value
     */
    public void addHeader(String name, String value) {
        headers.add(new BasicHeader(name, value));
    }

    /**
     * 设置默认的请求Header
     */
    private void defaultHeader() {
        this.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        this.addHeader("Accept-Encoding", "gzip,deflate,sdch");
        this.addHeader("Accept-Language", "zh-CN,zh;q=0.8");
        this.addHeader("Connection", "keep-alive");
        this.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36");
    }

    /**
     * HTTPS访问（允许信任自签证书，即信任所有证书）
     * @return
     * @author zhaoyy
     * @date 2014-5-9 下午5:46:58
     */
    private SSLConnectionSocketFactory getSslSocketFactory() {
        SSLConnectionSocketFactory sslSocketFactory = null;
        try {
            // 信任所有SSL
            TrustStrategy trustStore = new TrustSelfSignedStrategy();
            SSLContext sslcontext = new SSLContextBuilder().loadTrustMaterial(null, trustStore).build();
            sslSocketFactory = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sslSocketFactory;
    }

    /**
     * 设置代理
     * @param host 代理IP
     * @param port 代理端口
     * @param scheme 代理类型（HTTP,HTTPS）
     * @auther zhaoyy
     * @date 2014-4-12 上午2:18:22
     */
    public void setProxy(String host, int port, String scheme) {
        if ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)) {
            proxy = new HttpHost(host, port, scheme);
        } else {
            proxy = new HttpHost(host, port);
        }
        proxyConfig = RequestConfig.copy(requestConfig).setProxy(proxy).build();
    }

    /**
     * @Title: HTTP GET请求
     * @Author: zhaoyy 2016年10月18日 下午1:46:00
     * @param url 请求地址
     * @param params  请求参数
     * @param isProxy  是否设置代理
     * @return
     * @throws Exception
     */
    public String httpAlipyGet(String url, Map<String, String> params, boolean isProxy) throws Exception {
        return httpAlipyGet(url, headers, params, isProxy);
    }

    /**
     * @Title: HTTP GET请求
     * @Author: zhaoyy 2016年10月18日 下午1:46:00
     * @param url 请求地址
     * @param headers  请求头
     * @param params  请求参数 
     * @param isProxy  是否设置代理
     * @return
     * @throws Exception
     */
    public String httpAlipyGet(String url, List<Header> headers, Map<String, String> params, boolean isProxy) throws Exception {
        String html = null;
        CloseableHttpResponse response = get(url, headers, params, isProxy);
        if (response != null) {
            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    html = EntityUtils.toString(entity);
                }
            } finally {
                response.close();
            }
        }
        return html;
    }

    /**
     * @Title: HTTP POST请求
     * @Author: zhaoyy 2016年10月18日 下午1:46:00
     * @param url 请求地址
     * @param params  请求参数 
     * @param isProxy  是否设置代理
     * @return
     * @throws Exception
     */
    public String httpPost(String url, Map<String, String> params) throws Exception {
        return httpPost(url, headers, params);
    }

    /**
     * @Title: HTTP GET请求
     * @Author: zhaoyy 2016年10月18日 下午1:46:00
     * @param url 请求地址
     * @param headers  请求头
     * @param params  请求参数
     * @param isProxy  是否设置代理
     * @return
     * @throws Exception
     */
    public String httpGet(String url, List<Header> headers, Map<String, String> params, boolean isProxy) throws Exception {
        String html = null;
        CloseableHttpResponse response = get(url, headers, params, isProxy);
        if (response != null) {
            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    html = EntityUtils.toString(entity);
                }
            } finally {
                response.close();
            }
        }
        return html;
    }

    /**
     * @Title: HTTP POST请求
     * @Author: zhaoyy 2016年10月18日 下午1:46:00
     * @param url 请求地址
     * @param headers  请求头
     * @param params  请求参数 
     * @param isProxy  是否设置代理
     * @return
     * @throws Exception
     */
    public String httpPost(String url, List<Header> headers, Map<String, String> params) throws Exception {
        String html = null;
        CloseableHttpResponse response = post(url, headers, params, false);
        if (response != null) {
            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    html = EntityUtils.toString(entity);
                }
            } finally {
                response.close();
            }
        }
        return html;
    }

    /**
     * @Title: HTTP POST请求
     * @Author: zhaoyy 2016年10月18日 下午1:46:00
     * @param url 请求地址
     * @param headers  请求头
     * @param params  请求参数 JSON格式
     * @param isProxy  是否设置代理
     * @return
     * @throws Exception
     */
    public String httpPost(String url, List<Header> headers, String json) throws Exception {
        String html = null;
        CloseableHttpResponse response = post(url, headers, json, false);
        if (response != null) {
            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    html = EntityUtils.toString(entity);
                }
            } finally {
                response.close();
            }
        }
        return html;
    }

    /**
     * @Title: HTTP GET请求
     * @Author: zhaoyy 2016年10月18日 下午1:46:00
     * @param url 请求地址
     * @param headers  请求头
     * @param params  请求参数
     * @param isProxy  是否设置代理
     * @return
     * @throws Exception
     */
    private CloseableHttpResponse get(String url, List<Header> headers, Map<String, String> params, boolean isProxy) throws Exception {
        // 写入请求参数
        String parm = null;
        if (params != null && params.size() > 0) {
            parm = "";
            for (String key : params.keySet()) {
                parm += URLEncoder.encode(key, "UTF-8") + "=" + URLEncoder.encode(params.get(key), "UTF-8") + "&";
            }
            parm = parm.substring(0, parm.length() - 1);
        }
        HttpGet request = new HttpGet(url + (parm == null ? "" : "?" + parm));
        if (isProxy && proxyConfig != null) { // 设置代理
            request.setConfig(proxyConfig);
        }
        // 设置请求Header
        for (Header header : headers) {
            request.addHeader(header);
        }
        return httpclient.execute(request);
    }

    /**
     * @Title: HTTP POST请求
     * @Author: zhaoyy 2016年10月18日 下午1:44:59
     * @param url 请求地址
     * @param headers 请求头
     * @param params  请求参数
     * @param isProxy  是否设置代理
     * @return
     * @throws Exception
     */
    private CloseableHttpResponse post(String url, List<Header> headers, Map<String, String> params, boolean isProxy) throws Exception {
        HttpPost request = new HttpPost(url);
        if (isProxy && proxyConfig != null) { // 设置代理
            request.setConfig(proxyConfig);
        }
        // 写入请求参数
        List<NameValuePair> nvps = null;
        if (params != null && params.size() > 0) {
            nvps = new ArrayList<NameValuePair>();
            for (String key : params.keySet()) {
                nvps.add(new BasicNameValuePair(key, params.get(key)));
            }
            request.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
        }
        // 设置请求Header
        for (Header header : headers) {
            request.addHeader(header);
        }
        return httpclient.execute(request);
    }

    /**
     * @Title: HTTP POST请求
     * @Author: zhaoyy 2016年10月18日 下午1:43:26
     * @param url 请求地址
     * @param headers 请求头
     * @param json 请求参数 JSON格式
     * @param isProxy 是否设置代理
     * @return
     * @throws Exception
     */
    private CloseableHttpResponse post(String url, List<Header> headers, String json, boolean isProxy) throws Exception {
        HttpPost request = new HttpPost(url);
        if (isProxy && proxyConfig != null) { // 设置代理
            request.setConfig(proxyConfig);
        }
        request.addHeader(HTTP.CONTENT_TYPE, "application/json");
        // 写入请求参数
        StringEntity se = new StringEntity(json, ContentType.APPLICATION_JSON);
        request.setEntity(se);
        // 设置请求Header
        for (Header header : headers) {
            request.addHeader(header);
        }
        return httpclient.execute(request);
    }

    public void close() {
        try {
            httpclient.close();
            instance = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @Title: 自定义 HTTP POST请求
     * @Author: zhaoyy 2016年10月18日 下午1:42:04
     * @param url 请求地址
     * @param param 请求参数
     * @param headerparam 请求头参数
     * @param header 请求头值
     * @return
     */
    public String httpPost(String url, String param, String headerparam, String header) {
        OutputStreamWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            HttpURLConnection conn = null;
            // 打开和URL之间的连接
            conn = (HttpURLConnection) realUrl.openConnection();
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod("POST"); // POST方法
            // 设置通用的请求属性
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Host", "http://www.bpoint.com.au");
            conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
            conn.setRequestProperty(headerparam, header);
            conn.connect();
            // 获取URLConnection对象对应的输出流
            out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
            // 发送请求参数
            out.write(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }

    /**
     * @Title: HTTP POST请求
     * @Author: zhaoyy 2016年10月18日 下午1:40:41
     * @param url 请求地址
     * @param params 请求参数
     * @param encode 编码方式
     * @return
     * @throws Exception
     */
    public String httpPost(String url, Map<String, String> params, String encode) throws Exception {
        String html = null;
        CloseableHttpResponse response = null;
        HttpPost request = new HttpPost(url);
        // 写入请求参数
        List<NameValuePair> nvps = null;
        if (params != null && params.size() > 0) {
            nvps = new ArrayList<NameValuePair>();
            for (String key : params.keySet()) {
                nvps.add(new BasicNameValuePair(key, params.get(key)));
            }
            request.setEntity(new UrlEncodedFormEntity(nvps, encode));
        }
        response = httpclient.execute(request);
        if (response != null) {
            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    html = EntityUtils.toString(entity);
                }
            } finally {
                response.close();
            }
        }
        return html;
    }

    /**
     * @Title: HTTP GET请求
     * @Author: zhaoyy 2016年10月18日 下午1:38:53
     * @param url 请求地址
     * @param params 参数
     * @param isProxy 是否使用代理
     * @return
     * @throws Exception
     */
    public String httpGet(String url, Map<String, String> params, boolean isProxy) throws Exception {
        return httpAlipyGet(url, headers, params, isProxy);
    }

    /**
     * @Title: HTTP POST请求 原生请求
     * @Author: zhaoyy 2016年10月18日 下午1:38:53
     * @param url 请求地址
     * @param params 参数
     * @param isProxy 是否使用代理
     * @return
     * @throws Exception
     */
    public static String sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常！" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }
}
